package ChessEngine;

import boardData.Board;

/**
 * @author daniel Diese Bewertungsfunktion betrachtet außer der Anzahl und
 *         Wertigkeit der Figuren auch noch deren Position. Dazu werden
 *         sogenannte Piece-Square-Tables für die Bewertung der Position
 *         herangezogen. Außerdem wird das Brett noch nach bestimmten
 *         Formationen durchsucht,die auch mit bewertet werden. Die
 *         Wertigkkeiten für die Pice-Squaretables, als auch die Formationen und
 *         deren Wertung sind entnommen aus: Paulsen Philipp: Lernen
 *         unterschiedlicher Bewertungsfunktionen aus Schach-Spielprotokollen,
 *         Diplomarbeit 8 Juli 2009 zu finden unter:
 *         http://www.ke.tu-darmstadt.de/bibtex/attachments/single/145 (Stand
 *         31.07.2011)
 */
public class PieceSquareTableEvaluator extends SimpleEvaluator {

	// malus
	/*
	 * Befinden sich zwei Bauern einer Seite in derselben Linie behindern sie
	 * sich gegenseitig in ihrem Bewegungsspielraum und können einander keine
	 * Deckung geben. Daher wird eine solche Situation mit Punktabzug bestraft.
	 */
	final static int DOUBLE_PAWN = 10;

	/*
	 * Befindet sich auf keiner der benachbarten Linie ein weiterer Bauer der
	 * eigenen Seite, welcher Deckung bieten könnte, so führt dies ebenfalls zu
	 * einem Abzug
	 */
	final static int ISOLATED_PAWN = 20;
	/*
	 * Befindet sich kein Bauer hinter den Bauern auf den benachbarten Linien
	 * und kann somit nicht von diesen gedeckt werden so führt dies ebenfalls zu
	 * einem Malus bzw. Er steht hinter oder neben seinen Nachbarbauern. Das hat
	 * zur Folge, dass er nicht mehr durch andere Bauern geschützt werden kann.
	 * Auf der gleichen Linie steht kein gegnerischer Bauer. Die gegnerischen
	 * Schwerfiguren können den rückständigen Bauern also leicht von vorn
	 * angreifen.
	 */
	final static int BACKWARD_PAWN = 8;

	// bonus
	/*
	 * Hat ein Bauer weder auf der eigenen noch auf den beiden benachbarten
	 * Linien einen Bauern des Gegners vor sich und kann so nur noch durch den
	 * Einsatz von Figuren geschlagen werden, so wird dieser Vorteil mit einem
	 * Bonus belohnt
	 */
	final static int PASSED_PAWN = 20;
	/*
	 * Offene Linie: Wird ein Turm durch keinen Bauern auf seiner aktuellen
	 * Linie aufgehalten und kann sich frei Bewegen wird dies ebenfalls belohnt.
	 */
	final static int OPEN_LINE = 15;

	/*
	 * Wird ein Turm nicht mehr durch einen eigenen Bauern auf der aktuellen
	 * Linie behindert so fällt der Bonus etwas geringer aus. Durch das schlagen
	 * des gegnerischen Bauern kann aber schnell eine offene Linie geschaffen
	 * werden.
	 */
	final static int HALF_OPEN_LINE = 10;

	/*
	 * Turm auf 7ter Reihe: Hat ein Turm die zweite Reihe des Gegners, die 7te
	 * Reihe aus der eigenen Sicht, erreicht wird dies ebenfalls mit
	 * Bonuspunkten belohnt, da er von dieser Position aus gegnerische Bauern
	 * bedrohen kann die noch nicht gezogen wurden und in der Regel den Koenig
	 * in seinem Bewegungsspielraum stark einschraenkt.
	 */
	final static int ROOK_AT_7 = 20;
	
	public PieceSquareTableEvaluator(){
		
	}
	
	public PieceSquareTableEvaluator(Board b){
		for(int i=21;i<=98;i++){
			switch(b.getPiece(i)){
				case Board.BLACK_BISHOP: 
				case Board.BLACK_KING:
				case Board.BLACK_KNIGHT:
				case Board.BLACK_PAWN:
				case Board.BLACK_QUEEN:
				case Board.BLACK_ROOK:
				case Board.WHITE_BISHOP:
				case Board.WHITE_KING:
				case Board.WHITE_KNIGHT:
				case Board.WHITE_PAWN:
				case Board.WHITE_QUEEN:
				case Board.WHITE_ROOK:
			}
		}
	}

	@Override
	public int evaluate(Board b) {
		int materialCount = super.evaluate(b);

		return materialCount + calculateDoublePawnFactor(b)
				+ calculateIsolatedPawnFactor(b)
				+ calculateBackwardPawnFactor(b) + calculatePassedPawnFactor(b)
				+ calculateOpenLineFactor(b) + calculateHalfOpenLineFactor(b)
				+ calculateRookAt7Factor(b);
	}
	
	

	private int pieceSquareMaterialCount() {
		// TODO Auto-generated method stub
		return 0;
	}



	private int calculateRookAt7Factor(Board b) {
		final int whiteRookAt7 = calculateWhiteRookAt7(b);
		final int blackRoockAt7 = calculateBlackRookAt7(b);

		return whiteRookAt7 - blackRoockAt7;
	}

	private int calculateBlackRookAt7(Board b) {
		for (int i = 81; i <= 89; i++) {
			if (b.getPiece(i) == Board.BLACK_ROOK) {
				return -ROOK_AT_7;
			}
		}
		return 0;
	}

	private int calculateWhiteRookAt7(Board b) {
		for (int i = 31; i <= 39; i++) {
			if (b.getPiece(i) == Board.WHITE_ROOK) {
				return ROOK_AT_7;
			}
		}
		return 0;
	}

	private int calculateHalfOpenLineFactor(Board b) {
		return whiteHalfOpenLine(b) - blackHalfOpenLine(b);
	}

	private int whiteHalfOpenLine(Board b) {
		for (int i = 98; i <= 21; i--) {
			if (b.getPiece(i) == Board.WHITE_ROOK) {
				final int line = i % 10;
				for (int j = i; j >= 21; j -= 10) {
					final int piece = b.getPiece(j);
					if (piece == Board.WHITE_BISHOP
							|| piece == Board.WHITE_KING
							|| piece == Board.WHITE_KNIGHT
							|| piece == Board.WHITE_PAWN
							|| piece == Board.WHITE_QUEEN
							|| piece == Board.WHITE_ROOK) {
						return 0;
					}
				}

				for (int j = i; j <= 98; j += 10) {
					final int piece = b.getPiece(j);
					if (piece == Board.WHITE_BISHOP
							|| piece == Board.WHITE_KING
							|| piece == Board.WHITE_KNIGHT
							|| piece == Board.WHITE_PAWN
							|| piece == Board.WHITE_QUEEN
							|| piece == Board.WHITE_ROOK) {
						return 0;
					}
				}
			}
		}
		return HALF_OPEN_LINE;
	}

	private int blackHalfOpenLine(Board b) {
		for (int i = 21; i <= 98; i++) {
			if (b.getPiece(i) == Board.BLACK_ROOK) {
				final int line = i % 10;
				for (int j = i; j >= 21; j -= 10) {
					final int piece = b.getPiece(j);
					if (piece == Board.BLACK_BISHOP
							|| piece == Board.BLACK_KING
							|| piece == Board.BLACK_KNIGHT
							|| piece == Board.BLACK_PAWN
							|| piece == Board.BLACK_QUEEN
							|| piece == Board.BLACK_ROOK) {
						return 0;
					}
				}

				for (int j = i; j <= 98; j += 10) {
					final int piece = b.getPiece(j);
					if (piece == Board.BLACK_BISHOP
							|| piece == Board.BLACK_KING
							|| piece == Board.BLACK_KNIGHT
							|| piece == Board.BLACK_PAWN
							|| piece == Board.BLACK_QUEEN
							|| piece == Board.BLACK_ROOK) {
						return 0;
					}
				}
			}
		}
		return HALF_OPEN_LINE;
	}

	private int calculateOpenLineFactor(Board b) {

		return whiteOpenLineFactor(b) - blackOpenLineFactor(b);
	}

	private int whiteOpenLineFactor(Board b) {
		for (int i = 98; i <= 21; i--) {
			if (b.getPiece(i) == Board.WHITE_ROOK) {
				final int line = i % 10;
				boolean openLine = true;
				for (int j = line + 20; i <= 98; j += 10) {
					if (b.getPiece(j) != Board.EMPTY_FIELD) {
						openLine = false;
					}
				}
				if (openLine) {
					return OPEN_LINE;
				}
			}
		}
		return 0;
	}

	private int blackOpenLineFactor(Board b) {
		for (int i = 21; i <= 98; i++) {
			if (b.getPiece(i) == Board.BLACK_ROOK) {
				final int line = i % 10;
				boolean openLine = true;
				for (int j = line + 20; j <= 98; j += 10) {
					if (b.getPiece(j) != Board.EMPTY_FIELD) {
						openLine = false;
					}
				}
				if (openLine) {
					return -OPEN_LINE;
				}
			}
		}
		return 0;
	}

	private int calculatePassedPawnFactor(Board b) {
		return whitePassedPawn(b) - blackPassedPawn(b);
	}

	private int blackPassedPawn(Board b) {
		int result = 0;
		for (int i = 31; i <= 98; i++) {
			final int piece = b.getPiece(i);
			if (piece == Board.BLACK_PAWN) {
				// Eigene linie durch gegnerbauer blockiert
				boolean ownLineBlocked = false;
				for (int j = i % 10 + 30; j <= 98; j += 10) {
					if (b.getPiece(j) == Board.WHITE_PAWN) {
						ownLineBlocked = true;
						break;
					}
				}
				// linke linie durch gegnerbauer blockiert
				boolean leftLineBlocked = false;
				if (!ownLineBlocked
						&& b.getPiece(i % 10 - 1) != Board.ILLEGAL_FIELD) {
					for (int j = i % 10 + 30 - 1; i <= 98; i += 10) {
						if (b.getPiece(j) == Board.WHITE_PAWN) {
							leftLineBlocked = true;
							break;
						}
					}
				}

				// linke line durch gegnerbauer blockiert
				boolean rightLineBlocked = false;
				if (!ownLineBlocked && !leftLineBlocked
						&& b.getPiece(i % 10 + 1) != Board.ILLEGAL_FIELD) {
					for (int j = i % 10 + 30 + 1; i <= 98; i += 10) {
						if (b.getPiece(j) == Board.WHITE_PAWN) {
							leftLineBlocked = true;
							break;
						}
					}
				}

				if (!ownLineBlocked && !leftLineBlocked && !rightLineBlocked) {
					result -= PASSED_PAWN;
				}
			}
		}
		return result;
	}

	private int whitePassedPawn(Board b) {
		int result = 0;
		for (int i = 98; i >= 31; i--) {
			final int piece = b.getPiece(i);
			if (piece == Board.WHITE_PAWN) {
				// Eigene linie durch gegnerbauer blockiert
				boolean ownLineBlocked = false;
				for (int j = i % 10 + 30; j >= 21; j -= 10) {
					if (b.getPiece(j) == Board.BLACK_PAWN) {
						ownLineBlocked = true;
						break;
					}
				}
				// linke linie durch gegnerbauer blockiert
				boolean leftLineBlocked = false;
				if (!ownLineBlocked
						&& b.getPiece(i % 10 - 1) != Board.ILLEGAL_FIELD) {
					for (int j = i % 10 + 30 - 1; i >= 21; i -= 10) {
						if (b.getPiece(j) == Board.BLACK_PAWN) {
							leftLineBlocked = true;
							break;
						}
					}
				}

				// linke line durch gegnerbauer blockiert
				boolean rightLineBlocked = false;
				if (!ownLineBlocked && !leftLineBlocked
						&& b.getPiece(i % 10 + 1) != Board.ILLEGAL_FIELD) {
					for (int j = i % 10 + 30 + 1; i >= 31; i -= 10) {
						if (b.getPiece(j) == Board.BLACK_PAWN) {
							rightLineBlocked = true;
							break;
						}
					}
				}
				if (!ownLineBlocked && !leftLineBlocked && !rightLineBlocked) {
					result += PASSED_PAWN;
				}
			}
		}
		return result;
	}

	private int calculateBackwardPawnFactor(Board b) {
		return whiteBackwardPawn(b) - blackBackwardPawn(b);
	}

	private int blackBackwardPawn(Board b) {
		int result = 0;
		for (int i = 31; i <= 98; i++) {
			final int piece = b.getPiece(i);
			if (piece == Board.BLACK_PAWN) {
				if (b.getPiece(i - 11) == Board.BLACK_PAWN
						|| b.getPiece(i + 11) == Board.BLACK_PAWN) {
					continue;
				}
				boolean openLine = true;
				for (int j = i % 10 + 30; j <= 98; j += 10) {
					if (b.getPiece(j) == Board.EMPTY_FIELD) {
						continue;
					} else {
						openLine = false;
					}
				}
				if (openLine) {
					result += BACKWARD_PAWN;
				}
			}
		}
		return result;
	}

	private int whiteBackwardPawn(Board b) {
		int result = 0;
		for (int i = 88; i >= 21; i--) {
			final int piece = b.getPiece(i);
			if (piece == Board.WHITE_PAWN) {
				if (b.getPiece(i - 11) == Board.WHITE_PAWN
						|| b.getPiece(i + 11) == Board.WHITE_PAWN) {
					continue;
				}
				boolean openLine = true;
				for (int j = i % 10 + 80; j >= 21; j -= 10) {
					if (b.getPiece(j) == Board.EMPTY_FIELD) {
						continue;
					} else {
						openLine = false;
					}
				}
				if (openLine) {
					result += -BACKWARD_PAWN;
				}
			}
		}
		return result;
	}

	private int calculateIsolatedPawnFactor(Board b) {
		return whiteIsolatedPawn(b) - blackIsolatedPawn(b);
	}

	private int blackIsolatedPawn(Board b) {
		int result = 0;
		for (int i = 31; i <= 98; i++) {
			final int piece = b.getPiece(i);
			if (piece == Board.BLACK_PAWN) {
				if (b.getPiece(i - 1) == Board.BLACK_PAWN
						|| b.getPiece(i + 1) == Board.BLACK_PAWN) {
					continue;
				} else {
					result += ISOLATED_PAWN;
				}
			}
		}
		return result;
	}

	private int whiteIsolatedPawn(Board b) {
		int result = 0;
		for (int i = 31; i <= 98; i++) {
			final int piece = b.getPiece(i);
			if (piece == Board.WHITE_PAWN) {
				if (b.getPiece(i - 1) == Board.WHITE_PAWN
						|| b.getPiece(i + 1) == Board.WHITE_PAWN) {
					continue;
				} else {
					result += -ISOLATED_PAWN;
				}
			}
		}
		return result;
	}

	private int calculateDoublePawnFactor(Board b) {
		return whiteDoublePawn(b) - blackDoublePawn(b);
	}

	private int blackDoublePawn(Board b) {
		int result = 0;
		for (int i = 31; i <= 98; i++) {
			final int piece = b.getPiece(i);
			if (piece == Board.BLACK_PAWN) {
				for (int j = i; j <= 98; j += 10) {
					if (b.getPiece(j) == Board.BLACK_PAWN) {
						result += DOUBLE_PAWN;
					}
				}
			}
		}
		return result;
	}

	private int whiteDoublePawn(Board b) {
		int result = 0;
		for (int i = 88; i >= 21; i-=10) {
			final int piece = b.getPiece(i);
			if (piece == Board.WHITE_PAWN) {
				for (int j = i; j >= 21; j -= 10) {
					if (b.getPiece(j) == Board.WHITE_PAWN) {
						result += -DOUBLE_PAWN;
					}
				}
			}
		}
		return result;
	}

}
